﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GraphTools.OSM
{
    public class OSMWay : OSMBase
    {
        public IList<int> Nodes { get; set; }

        public OSMWay(int ID, int Version, DateTime Timestamp, IList<int> Nodes, IDictionary<string, string> Tags) :
            base(ID,Version,Timestamp,Tags)
        {
            this.Nodes = Nodes;
        }

        public override bool Equals(object obj)
        {
            return Enumerable.SequenceEqual<int>(Nodes, obj as List<int>);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public void Split(int SplitableNodeId, out OSMWay way1, out OSMWay way2)
        {
            way1 = new OSMWay(GetNextID(), 1, DateTime.Now, new List<int>(), Tags);
            way2 = new OSMWay(GetNextID(), 1, DateTime.Now, new List<int>(), Tags);      
            if (Nodes.Count==0) return;

            int index = Nodes.IndexOf(SplitableNodeId);
            if (index < 0)
            {
                way2.Nodes.ToList().AddRange(Nodes);
                return;
            }

            (way1.Nodes as List<int>).AddRange(Nodes.ToList().GetRange(0, index + 1));
            (way2.Nodes as List<int>).AddRange(Nodes.ToList().GetRange(index, Nodes.Count - index));
        }

        public bool IsSamePath(OSMWay way)
        {
            if (Nodes.Count != way.Nodes.Count) return false;
            else
            return (Enumerable.SequenceEqual<int>(Nodes, way.Nodes) || Enumerable.SequenceEqual<int>(Nodes, way.Nodes.Reverse<int>()));
        }

        public ICollection<OSMWay> SplitN(ICollection<OSMNode> splitPoints)
        {
            ICollection<OSMWay> result = new List<OSMWay>();
            List<OrderablePair> orderedSplitPoints = new List<OrderablePair>();
            //collect points are on the ways
            foreach (OSMNode sp in splitPoints)
            {
                int index = Nodes.IndexOf(sp.ID);
                if (index >= 0) orderedSplitPoints.Add(new OrderablePair(index, sp));
            }
            //sort by index
            orderedSplitPoints.Sort();

            //split N times
            OSMWay subway1, subway2, actual = this;
            foreach (OrderablePair op in orderedSplitPoints)
            {
                actual.Split((op.Value as OSMNode).ID, out subway1, out subway2);
                if (subway1.Nodes.Count > 1) result.Add(subway1); //1 node ways invalids
                actual = subway2;
            }
            //add the last subway
            if (actual.Nodes.Count > 1) result.Add(actual);
            return result;
        }

        protected class OrderablePair : IComparable
        {
            public int Order { get; set; }
            public Object Value { get; set; }

            public OrderablePair() { }
            public OrderablePair(int Order, Object Value)
            {
                this.Order = Order;
                this.Value = Value;
            }

            public int CompareTo(object obj)
            {
                return Order - (obj as OrderablePair).Order;
            }
        }

    }
}
